#!/usr/local/bin/ruby -w

# fibonacci_chess
#
#  Created by James Edward Gray II on 2005-06-20.
#  Copyright 2005 Gray Productions. All rights reserved.

require "chess"

# An enhanced chess board for playing Fibonacci Chess.
class FibonacciBoard < Chess::Board
	# Setup chess board and initialize move count sequence.
	def initialize(  )
		super
		
		@fib1  = nil
		@fib2  = nil
		@count = 1
	end
	
	# Advance turn, as players complete moves in the Fibonacci sequence.
	def next_turn(  )
		if @fib1.nil?
			@fib1 = 1
		elsif @fib2.nil?
			@fib2 = 2
			next_turn if in_check?(@turn == :white ? :black : :white)
		elsif @count.zero? or in_check?(@turn == :white ? :black : :white)
			@fib1, @fib2 = @fib2, @fib1 + @fib2
			@count = @fib2 - 1
		else
			@count -= 1
			return
		end

		super
	end
	
	# Return a String description of the moves remaining.
	def moves_remaining(  )
		if @fib1.nil? or @fib2.nil? or @count.zero?
			"last move"
		else
			"#{@count + 1} moves"
		end
	end
end

board = FibonacciBoard.new

puts
puts "Welcome to Ruby Quiz Fibonacci Chess."

# player move loop
loop do
	# show board
	puts
	puts board
	puts

	# watch for end conditions
	if board.in_checkmate?
		puts "Checkmate!  " +
		     "It's #{board.turn == :white ? 'Black' : 'White'}'s game."
		puts
		break
	elsif board.in_stalemate?
		puts "Stalemate."
		puts
		break
	elsif board.in_check?
		puts "Check."
	end

	# move input loop
	move = nil
	loop do
		print "#{board.turn.to_s.capitalize}'s Move " +
		      "(#{board.moves_remaining}):  "
		move = $stdin.gets.chomp
		
		# validate move
		moves = board.moves
		if move !~ /^\s*([a-h][1-8])\s*([a-h][1-8])\s*$/
			puts "Invalid move format.  Use from to.  (Example:  e2 e4.)"
		elsif board[$1].nil?
			puts "No piece on that square."
		elsif board[$1].color != board.turn
			puts "That's not your piece to move."
		elsif board.in_check? and ( (m = moves.assoc($1)).nil? or
			                        not m.last.include?($2) )
			puts "You must move out of check."
		elsif not (board[$1].captures + board[$1].moves).include?($2)
			puts "That piece can't move to that square."
		elsif ((m = moves.assoc($1)).nil? or not m.last.include?($2))
			puts "You can't move into check."
		else
			break
		end
	end
	
	# make move, with promotion if needed
	if board[$1].is_a?(Chess::Pawn) and $2[1, 1] == "8"
		from, to = $1, $2

		print "Promote to (k, b, r, or q)?  "
		promote = $stdin.gets.chomp
		
		case promote.downcase[0, 1]
		when "k"
			board.move($1, $2, Chess::Knight)
		when "b"
			board.move($1, $2, Chess::Bishop)
		when "r"
			board.move($1, $2, Chess::Rook)
		else
			board.move($1, $2, Chess::Queen)
		end
	else
		board.move($1, $2)
	end
end
